package cn.wizzer.app.crown.modules.services.impl;

import cn.wizzer.app.crown.commons.util.DateUtil;
import cn.wizzer.app.crown.modules.models.CrownViewPoint;
import cn.wizzer.app.crown.modules.models.CrownViewPointLabel;
import cn.wizzer.app.crown.modules.models.CrownViewPointOrder;
import cn.wizzer.app.crown.modules.models.caches.CrownMatchSimplex;
import cn.wizzer.app.crown.modules.models.constant.CrownConstant;
import cn.wizzer.app.crown.modules.models.enums.MatchTypeEnum;
import cn.wizzer.app.crown.modules.models.vo.*;
import cn.wizzer.app.crown.modules.services.CrownMatchService;
import cn.wizzer.app.crown.modules.services.ViewPointLabelService;
import cn.wizzer.app.crown.modules.services.ViewPointOrderService;
import cn.wizzer.app.crown.modules.services.ViewPointService;
import cn.wizzer.app.sys.modules.models.SysMsg;
import cn.wizzer.app.sys.modules.models.SysParam;
import cn.wizzer.app.sys.modules.services.SysMsgService;
import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.app.sys.modules.services.SysSensitiveService;
import cn.wizzer.app.user.modules.models.User;
import cn.wizzer.app.user.modules.models.UserAccountRecord;
import cn.wizzer.app.user.modules.models.enums.BizTypeEnum;
import cn.wizzer.app.user.modules.models.enums.ViewStatusEnum;
import cn.wizzer.app.user.modules.models.vo.UserFocusVo;
import cn.wizzer.app.user.modules.services.UserRestrictionService;
import cn.wizzer.app.user.modules.services.UserService;
import cn.wizzer.app.user.modules.services.account.UserAccountRecordService;
import cn.wizzer.framework.base.Result;
import cn.wizzer.framework.base.exceptions.BizException;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.Id;
import cn.wizzer.framework.util.JSONUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@IocBean(args = "refer:dao")
@Service(interfaceClass = ViewPointService.class)
public class ViewPointServiceImpl extends BaseServiceImpl<CrownViewPoint> implements ViewPointService {

    @Inject
    private ViewPointOrderService orderService;

    @Inject
    private ViewPointLabelService labelService;

    @Reference
    @Inject
    private UserAccountRecordService accountRecordService;

    @Reference
    @Inject
    private UserRestrictionService restrictionService;

    @Inject
    private CrownMatchService matchService;

    @Inject
    private CommonDBService dbService;

    @Reference
    @Inject
    private SysMsgService sysMsgService;

    @Reference
    @Inject
    private SysParamService sysParamService;

    @Inject
    @Reference
    private UserService userService;

    @Inject
    @Reference
    private SysSensitiveService sysSensitiveService;

    public ViewPointServiceImpl(Dao dao) {
        super(dao);
    }




    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public synchronized void settle() {

        Sql sql = Sqls.create("select v.*, " +
                "m.mb_in_ball_hf mbInBallHalf, mb_in_ball mbInBall, tg_in_ball_hf tgInBallHalf, tg_in_ball tgInBall from crown_view_point v");
        sql.appendSourceSql("left join crown_match m on m.id = v.matchId");
        //观点结果未待确认，对应赛事已有赛过
        sql.appendSourceSql("where v.result = 0 and m.stage=@stage");
        sql.setParam("stage", CrownConstant.FINISHED);
        List<CrownMatchViewPointVO> list = dbService.list(CrownMatchViewPointVO.class, sql.toString());
        //判断结果
        for (CrownMatchViewPointVO crownMatchViewPointVO : list) {
            BigDecimal rate = new BigDecimal(restrictionService.initCache(crownMatchViewPointVO.getUserId()).getViewRate()).divide(new BigDecimal(100));
            boolean result = false;
            //胜负判定
            if (Strings.isNotBlank(crownMatchViewPointVO.getMbInBall())) {

                //作者观点
                CrownMatchSimplex selectedOption = JSONUtil.parseStringToJavaBean(CrownMatchSimplex.class, crownMatchViewPointVO.getSelectedOption());

                //足球
                if (crownMatchViewPointVO.getMatchType().equals(MatchTypeEnum.FOOTBALL)) {
                    switch (selectedOption.getNo1()) {
                        // 全场独赢玩法
                        case 1:
                            result = this.ftFullCourtWinSimplex(selectedOption, crownMatchViewPointVO);
                            break;
                        // 全场让球玩法
                        case 2:
                            result = this.ftFullCourtLetBall(selectedOption, crownMatchViewPointVO);
                            break;
                        // 全场大小玩法
                        case 3:
                            result = this.ftFullCourtBigOrSmall(selectedOption, crownMatchViewPointVO);
                            break;
                        // 全场单双玩法
                        case 4:
                            result = this.ftFullCourtSingleOrDouble(selectedOption, crownMatchViewPointVO);
                            break;
                        // 半场独赢玩法
                        case 5:
                            result = this.ftHalfCourtWinSimplex(selectedOption, crownMatchViewPointVO);
                            break;
                        // 半场让球玩法
                        case 6:
                            result = this.ftHalfCourtLetBall(selectedOption, crownMatchViewPointVO);
                            break;
                        // 半场大小玩法
                        case 7:
                            result = this.ftHalfCourtBigOrSmall(selectedOption, crownMatchViewPointVO);
                            break;
                    }
                } else
                    //篮球
                    if (crownMatchViewPointVO.getMatchType().equals(MatchTypeEnum.BASKETBALL)) {
                        switch (selectedOption.getNo1()) {
                            // 全场独赢玩法
                            case 1:
                                result = this.bkFullCourtWinSimplex(selectedOption, crownMatchViewPointVO);
                                break;
                            // 全场让球玩法
                            case 2:
                                result = this.bkFullCourtLetBall(selectedOption, crownMatchViewPointVO);
                                break;
                            // 全场大小玩法
                            case 3:
                                result = this.bkFullCourtBigOrSmall(selectedOption, crownMatchViewPointVO);
                                break;
                            // 球队得分大玩法
                            case 4:
                                result = this.bkTeamScoreBig(selectedOption, crownMatchViewPointVO);
                                break;
                        }
                    }

                // 未中
                if (!result) {
                    crownMatchViewPointVO.setResult(-1);
                    //不是免费的
                    if (crownMatchViewPointVO.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                        if (crownMatchViewPointVO.getRefundable()) {
                            for (CrownViewPointOrder order : orderService.query(Cnd.where("vpId", "=", crownMatchViewPointVO.getId()))) {
                                accountRecordService.add(order.getUserId(), crownMatchViewPointVO.getPrice(), BizTypeEnum.REFUND_VIEW_POINT, order.getId());
                            }
                        }
                        //分黑钱给笔者
                        else {
                            for (CrownViewPointOrder order : orderService.query(Cnd.where("vpId", "=", crownMatchViewPointVO.getId()))) {
                                accountRecordService.add(crownMatchViewPointVO.getUserId(), crownMatchViewPointVO.getPrice().multiply(rate), BizTypeEnum.REFUND_VIEW_POINT, order.getId());
                            }
                        }
                    }
                } else {
                    crownMatchViewPointVO.setResult(1);
                    //结算每笔订单流水到发布者
                    if (crownMatchViewPointVO.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                        for (CrownViewPointOrder order : orderService.query(Cnd.where("vpId", "=", crownMatchViewPointVO.getId()))) {
                            accountRecordService.add(crownMatchViewPointVO.getUserId(), crownMatchViewPointVO.getPrice().multiply(rate), BizTypeEnum.SELL_VIEW_POINT, order.getId());
                        }

                    }
                }
                //结果入库
                this.update(Chain.make("result", crownMatchViewPointVO.getResult()), Cnd.where("id", "=", crownMatchViewPointVO.getId()));
                //上统计
                labelService.statistics(crownMatchViewPointVO);
            }

        }
        //赛事异常的观点订单进行退款
        sql.setParam("stage", CrownConstant.OTHER);
        List<CrownMatchViewPointVO> others = dbService.list(CrownMatchViewPointVO.class, sql.toString());
        for (CrownMatchViewPointVO other : others) {
            for (CrownViewPointOrder order : orderService.query(Cnd.where("vpId", "=", other.getId()))) {
                accountRecordService.add(order.getUserId(), other.getPrice(), BizTypeEnum.REFUND_VIEW_POINT, order.getId());
            }
        }

    }

    /**
     * 统计上周用户发布的观点数、命中数及回报率
     */
    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void viewPointLabelWeekStatistics() {
        //一周前的时间 日 * 时 * 分 * 秒
        long lastWeek = System.currentTimeMillis() / 1000 - (7 * 24 * 60 * 60);
        //关闭之前的周统计记录
        labelService.update(Chain.make("delFlag", 1), Cnd.where("type", "=", "week").and("delFlag", "=", 0));
        //查询上周发布的所有观点，观点未删除且创建时间大于一周前的时间，且发布者必须为已认证状态
        Sql sql = Sqls.create("SELECT cvp.* " +
                "FROM crown_view_point cvp " +
                "LEFT JOIN user u ON cvp.userId = u.id " +
                "WHERE cvp.delFlag = 0 " +
                "AND cvp.ctAt >= @lastWeek " +
                "AND u.certified = 1 ");
        sql.setParam("lastWeek", lastWeek);
        List<CrownViewPoint> crownViewPoints = this.listEntity(sql);
        Map<String, List<CrownViewPoint>> map = new HashMap<>();
        for (CrownViewPoint crownViewPoint : crownViewPoints) {
            List<CrownViewPoint> list = map.get(crownViewPoint.getUserId());
            if (list == null) {
                list = new ArrayList<>();
            }
            list.add(crownViewPoint);
            map.put(crownViewPoint.getUserId(), list);
        }
        //生成统计记录
        for (String key : map.keySet()) {
            List<CrownViewPoint> list = map.get(key);
            BigDecimal totalOdds = BigDecimal.ZERO;
            for (CrownViewPoint crownViewPoint : list) {
                //中奖时累加回报率
                if (crownViewPoint.getResult() == 1) {
                    totalOdds = totalOdds.add(crownViewPoint.getOdds());
                }
            }
            CrownViewPointLabel label = new CrownViewPointLabel();
            label.setMatchCount(list.size());
            label.setTotalOdds(totalOdds.setScale(2, RoundingMode.DOWN));
            label.setWinCount(Math.toIntExact(list.stream().filter(vp -> vp.getResult().equals(1)).count()));
            label.setUserId(key);
            label.setType("week");
            this.insert(label);
        }
    }

    /**
     * 球队得分大玩法
     *
     * @param selectedOption
     * @param vpv
     * @return
     */
    private boolean bkTeamScoreBig(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        // 系数
        double coeNum = Math.abs(Double.parseDouble(selectedOption.getCoeNum()));
        int mbFullInBall;
        int tgFullInBall;
        // 获取主客队比分
        try {
            mbFullInBall = Integer.parseInt(vpv.getMbInBall());
            tgFullInBall = Integer.parseInt(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        // 如果下注的是主队
        if (1 == no3) {
            // 如果主队比分大于系数 全赢
            if (mbFullInBall > coeNum) {
                return true;
            }
            // 否则如果主队比分等于系数 走水
            else if (mbFullInBall == coeNum) {
                return false;
            }
            // 否则(主队比分小于系数) 全输
            else {
                return false;
            }
        } else {
            // 如果客队比分大于系数 全赢
            if (tgFullInBall > coeNum) {
                return true;
            }
            // 否则如果客队比分等于系数 走水
            else if (tgFullInBall == coeNum) {
                return false;
            }
            // 否则(客队比分小于系数) 全输
            else {
                return false;
            }
        }
    }

    /**
     * 全场大小玩法
     *
     * @param selectedOption
     * @return
     */
    private boolean bkFullCourtBigOrSmall(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        int mbInBall;
        int tgInBall;
        // 获取主客队比分
        try {
            mbInBall = Integer.parseInt(vpv.getMbInBall());
            tgInBall = Integer.parseInt(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        // 全场得分 = 主队全场得分 + 客队全场得分
        int fullInBall = mbInBall + tgInBall;
        // 篮球的都是单系数
        double coeNum = Double.parseDouble(selectedOption.getCoeNum());
        // 如果全场得分大于系数
        if (fullInBall > coeNum) {
            // 下注no3=1的位置 全赢
            if (1 == no3) {
                return true;
            } else {
                // no3=2的位置 全输
                return false;
            }
        }
        // 如果全场得分小于系数
        else if (fullInBall < coeNum) {
            // 下注no3=1的位置 全输
            if (1 == no3) {
                return false;
            } else {
                // no3=2的位置 全赢
                return true;
            }
        }
        // 如果全场得分等于系数，走水。
        else {
            return false;
        }
    }


    /**
     * 全场让球玩法
     *
     * @param selectedOption
     * @param vpv
     * @return
     */
    private boolean bkFullCourtLetBall(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        int mbFullInBall;
        int tgFullInBall;
        // 获取主客队比分
        try {
            mbFullInBall = Integer.parseInt(vpv.getMbInBall());
            tgFullInBall = Integer.parseInt(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        boolean mbIsStrong = (1 == selectedOption.getNo3() && !selectedOption.getCoeNum().contains("-"))
                || (2 == selectedOption.getNo3() && selectedOption.getCoeNum().contains("-"));
        // 主队是强队
        if (mbIsStrong) {
            // 篮球是单系数
            double coeNum = Math.abs(Double.parseDouble(selectedOption.getCoeNum()));
            // 主队得分 - 客队得分 - 系数 > 0
            if (mbFullInBall - tgFullInBall - coeNum > 0) {
                // 下注主队 全赢
                if (1 == no3) {
                    return true;
                } else {
                    // 下注客队 全输
                    return false;
                }
            }
            // 主队得分 - 客队得分 - 系数 = 0
            else if (mbFullInBall - tgFullInBall - coeNum == 0) {
                // 下注主队 走水.下注客队 走水
                return false;
            }
            // 主队得分 - 客队得分 - 系数 < 0
            else {
                // 下注主队 全输
                if (1 == no3) {
                    return false;
                } else {
                    // 下注客队 全赢
                    return true;
                }
            }
        } else {
            // 客队是强队
            // 单系数
            double coeNum = Math.abs(Double.parseDouble(selectedOption.getCoeNum()));
            // 客队得分 - 主队得分 - 系数 > 0
            if (tgFullInBall - mbFullInBall - coeNum > 0) {
                // 下注客队 全赢
                if (2 == no3) {
                    return true;
                } else {
                    // 下注主队 全输
                    return false;
                }
            }
            // 客队得分 - 主队得分 - 系数 = 0
            else if (tgFullInBall - mbFullInBall - coeNum == 0) {
                // 下注主队 走水.下注客队 走水
                return false;
            }
            // 客队得分 - 主队得分 - 系数 < 0
            else {
                // 下注客队 全输
                if (2 == no3) {
                    return false;
                } else {
                    // 下注主队 全赢
                    return true;
                }
            }
        }
    }

    /**
     * 半场大小玩法
     *
     * @param selectedOption
     * @return
     */
    private boolean ftHalfCourtBigOrSmall(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        int mbHalfInBall;
        int tgHalfInBall;
        // 获取主客队比分
        try {
            mbHalfInBall = Integer.parseInt(vpv.getMbInBallHalf());
            tgHalfInBall = Integer.parseInt(vpv.getTgInBallHalf());
        }catch (Exception e){
            return false;
        }
        // 半场得分 = 主队半场得分 + 客队半场得分
        int haflInBall = mbHalfInBall + tgHalfInBall;
        // 单系数
        if (!selectedOption.getCoeNum().contains("/")) {
            double coeNum = Double.parseDouble(selectedOption.getCoeNum());
            // 如果半场得分大于系数
            if (haflInBall > coeNum) {
                // 下注no3=1的位置 全赢
                if (1 == no3) {
                    return true;
                } else {
                    // no3=2的位置 全输
                    return false;
                }
            }
            // 如果半场得分小于系数
            else if (haflInBall < coeNum) {
                // 下注no3=1的位置 全输
                if (1 == no3) {
                    return false;
                } else {
                    // no3=2的位置 全赢
                    return true;
                }
            }
            // 如果半场得分等于系数，走水。
            else {
                return false;
            }
        } else {
            // 双系数
            double coeNumOne = Double.parseDouble(selectedOption.getCoeNum().split("/")[0]);
            double coeNumTwo = Double.parseDouble(selectedOption.getCoeNum().split("/")[1]);
            // 全场得分 > 系数1 && 全场得分 > 系数2
            if (haflInBall > coeNumOne && haflInBall > coeNumTwo) {
                // 下注no3=1的位置 全赢
                if (1 == no3) {
                    return true;
                } else {
                    // 下注no3=2的位置 全输
                    return false;
                }
            }
            // 全场得分 > 系数1 && 全场得分 = 系数2
            else if (haflInBall > coeNumOne && haflInBall == coeNumTwo) {
                // 下注no3=1的位置 半赢
                if (1 == no3) {
                    return true;
                } else {
                    // 下注no3=2的位置 半输
                    return false;
                }
            }
            // 全场得分 == 系数1 && 全场得分 < 系数2
            else if (haflInBall == coeNumOne && haflInBall < coeNumTwo) {
                // 下注no3=1 半输
                if (1 == no3) {
                    return false;
                } else {
                    // 下注no3=2 半赢
                    return true;
                }
            }
            // 全场得分 < 系数1 && 全场得分 < 系数2
            else if (haflInBall < coeNumOne && haflInBall < coeNumTwo) {
                // 下注no3=1 全输
                if (1 == no3) {
                    return false;
                } else {
                    // 下注no3=2 全赢
                    return true;
                }
            }
            // 否则 系数可能有误
            else {
                throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
            }
        }
    }

    /**
     * 半场让球玩法
     *
     * @param selectedOption
     * @param vpv
     * @return
     */
    private boolean ftHalfCourtLetBall(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        int mbHalfInBall;
        int tgHalfInBall;
        // 获取主客队比分
        try {
            mbHalfInBall = Integer.parseInt(vpv.getMbInBallHalf());
            tgHalfInBall = Integer.parseInt(vpv.getTgInBallHalf());
        }catch (Exception e){
            return false;
        }
        boolean mbIsStrong = (1 == selectedOption.getNo3() && !selectedOption.getCoeNum().contains("-"))
                || (2 == selectedOption.getNo3() && selectedOption.getCoeNum().contains("-"));
        // 主队是强队
        if (mbIsStrong) {
            // 单系数
            if (!selectedOption.getCoeNum().contains("/")) {
                double coeNum = Math.abs(Double.parseDouble(selectedOption.getCoeNum()));
                // 主队得分 - 客队得分 - 系数 > 0
                if (mbHalfInBall - tgHalfInBall - coeNum > 0) {
                    // 下注主队 全赢
                    if (1 == no3) {
                        return true;
                    } else {
                        // 下注客队 全输
                        return false;
                    }
                }
                // 主队得分 - 客队得分 - 系数 = 0
                else if (mbHalfInBall - tgHalfInBall - coeNum == 0) {
                    // 下注主队 走水.下注客队 走水
                    return false;
                }
                // 主队得分 - 客队得分 - 系数 < 0
                else {
                    // 下注主队 全输
                    if (1 == no3) {
                        return false;
                    } else {
                        // 下注客队 全赢
                        return true;
                    }
                }
            } else {
                // 双系数(如"0.5 / 1")
                double coeNumOne = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[0]));
                double coeNumTwo = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[1]));
                // 主队得分 - 客队得分 - 系数1 > 0 && 主队得分 - 客队得分 - 系数2 > 0
                if (mbHalfInBall - tgHalfInBall - coeNumOne > 0 && mbHalfInBall - tgHalfInBall - coeNumTwo > 0) {
                    // 下注主队 全赢
                    if (1 == no3) {
                        return true;
                    } else {
                        // 下注客队 全输
                        return false;
                    }
                }
                // 主队得分 - 客队得分 - 系数1 > 0 && 主队得分 - 客队得分 - 系数2 = 0
                else if (mbHalfInBall - tgHalfInBall - coeNumOne > 0 && mbHalfInBall - tgHalfInBall - coeNumTwo == 0) {
                    // 下注主队 半赢
                    if (1 == no3) {
                        return true;
                    } else {
                        // 下注客队 半输
                        return false;
                    }
                }
                // 主队得分 - 客队得分 - 系数1 == 0 && 主队得分 - 客队得分 - 系数2 < 0
                else if (mbHalfInBall - tgHalfInBall - coeNumOne == 0 && mbHalfInBall - tgHalfInBall - coeNumTwo < 0) {
                    // 下注主队 半输
                    if (1 == no3) {
                        return false;
                    } else {
                        // 下注客队 半赢
                        return true;
                    }
                }
                // 主队得分 - 客队得分 - 系数1 < 0 && 主队得分 - 客队得分 - 系数2 < 0
                else if (mbHalfInBall - tgHalfInBall - coeNumOne < 0 && mbHalfInBall - tgHalfInBall - coeNumTwo < 0) {
                    // 下注主队 全输
                    if (1 == no3) {
                        return false;
                    } else {
                        // 下注客队 全赢
                        return true;
                    }
                }
                // 否则 系数可能有误
                else {
                    throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
                }
            }
        } else {
            // 客队是强队
            // 单系数
            if (!selectedOption.getCoeNum().contains("/")) {
                double coeNum = Math.abs(Double.parseDouble(selectedOption.getCoeNum()));
                // 客队得分 - 主队得分 - 系数 > 0
                if (tgHalfInBall - mbHalfInBall - coeNum > 0) {
                    // 下注客队 全赢
                    if (2 == no3) {
                        return true;
                    } else {
                        // 下注主队 全输
                        return false;
                    }
                }
                // 客队得分 - 主队得分 - 系数 = 0
                else if (tgHalfInBall - mbHalfInBall - coeNum == 0) {
                    // 下注主队 走水.下注客队 走水
                    return false;
                }
                // 客队得分 - 主队得分 - 系数 < 0
                else {
                    // 下注客队 全输
                    if (2 == no3) {
                        return false;
                    } else {
                        // 下注主队 全赢
                        return true;
                    }
                }
            } else {
                // 双系数(如"0.5 / 1")
                double coeNumOne = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[0]));
                double coeNumTwo = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[1]));
                // 客队得分 - 主队得分 - 系数1 > 0 && 客队得分 - 主队得分 - 系数2 > 0
                if (tgHalfInBall - mbHalfInBall - coeNumOne > 0 && tgHalfInBall - mbHalfInBall - coeNumTwo > 0) {
                    // 下注客队 全赢
                    if (2 == no3) {
                        return true;
                    } else {
                        // 下注主队 全输
                        return false;
                    }
                }
                // 客队得分 - 主队得分 - 系数1 > 0 && 客队得分 - 主队得分 - 系数2 = 0
                else if (tgHalfInBall - mbHalfInBall - coeNumOne > 0 && tgHalfInBall - mbHalfInBall - coeNumTwo == 0) {
                    // 下注客队 半赢
                    if (2 == no3) {
                        return true;
                    } else {
                        // 下注主队 半输
                        return false;
                    }
                }
                // 客队得分 - 主队得分 - 系数1 == 0 && 客队得分 - 主队得分 - 系数2 < 0
                else if (tgHalfInBall - mbHalfInBall - coeNumOne == 0 && tgHalfInBall - mbHalfInBall - coeNumTwo < 0) {
                    // 下注客队 半输
                    if (2 == no3) {
                        return false;
                    } else {
                        // 下注主队 半赢
                        return true;
                    }
                }
                // 客队得分 - 主队得分 - 系数1 < 0 && 客队得分 - 主队得分 - 系数2 < 0
                else if (tgHalfInBall - mbHalfInBall - coeNumOne < 0 && tgHalfInBall - mbHalfInBall - coeNumTwo < 0) {
                    // 下注客队 全输
                    if (2 == no3) {
                        return false;
                    } else {
                        // 下注主队 全赢
                        return true;
                    }
                }
                // 否则 系数可能有误
                else {
                    throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
                }
            }
        }
    }

    private boolean ftHalfCourtWinSimplex(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // no3是下注的内容
        int no3 = selectedOption.getNo3();
        Integer mbHalfInBall;
        Integer tgHalfInBall;
        // 获取主客队比分
        try {
            mbHalfInBall = Integer.valueOf(vpv.getMbInBallHalf());
            tgHalfInBall = Integer.valueOf(vpv.getTgInBallHalf());
        }catch (Exception e){
            return false;
        }
        // 如果no3 = 1 主队比分 > 客队比分 中奖
        if (1 == no3 && (mbHalfInBall > tgHalfInBall)) {
            return true;
        }
        // 如果no3 = 2 客队比分 > 主队比分 中奖
        else if (2 == no3 && (tgHalfInBall > mbHalfInBall)) {
            return true;
        }
        // 如果no3 = 3 客队比分 = 主队比分 中奖
        else if (3 == no3 && (tgHalfInBall.equals(mbHalfInBall))) {
            return true;
        }
        // 否则 全输
        else {
            return false;
        }
    }

    private boolean ftFullCourtSingleOrDouble(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        int mbInBall;
        int tgInBall;
        // 获取主客队比分
        try {
            mbInBall = Integer.parseInt(vpv.getMbInBall());
            tgInBall = Integer.parseInt(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        // 全场比分为单数时
        if ((mbInBall + tgInBall) % 2 == 1) {
            // 下注no3=1的位置 全赢
            if (1 == no3) {
                return true;
            } else {
                // 下注no3=2的位置 全输
                return false;
            }
        } else {
            // 全场比分为双数时
            // 下注no3=2的位置 全赢
            if (2 == no3) {
                return true;
            } else {
                // 下注no3=1的位置 全输
                return false;
            }
        }
    }

    /**
     * @param selectedOption 足球全场大小
     * @return
     */
    private boolean ftFullCourtBigOrSmall(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        int mbInBall;
        int tgInBall;
        // 获取主客队比分
        try {
            mbInBall = Integer.parseInt(vpv.getMbInBall());
            tgInBall = Integer.parseInt(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        // 全场得分 = 主队全场得分 + 客队全场得分
        int fullInBall = mbInBall + tgInBall;
        // 单系数
        if (!selectedOption.getCoeNum().contains("/")) {
            double coeNum = Double.parseDouble(selectedOption.getCoeNum());
            // 如果全场得分大于系数
            if (fullInBall > coeNum) {
                // 下注no3=1的位置 全赢
                if (1 == no3) {
                    return true;
                } else {
                    // no3=2的位置 全输
                    return false;
                }
            }
            // 如果全场得分小于系数
            else if (fullInBall < coeNum) {
                // 下注no3=1的位置 全输
                if (1 == no3) {
                    return false;
                } else {
                    // no3=2的位置 全赢
                    return true;
                }
            }
            // 如果全场得分等于系数，走水。
            else {
                return false;
            }
        } else {
            // 双系数
            double coeNumOne = Double.parseDouble(selectedOption.getCoeNum().split("/")[0]);
            double coeNumTwo = Double.parseDouble(selectedOption.getCoeNum().split("/")[1]);
            // 全场得分 > 系数1 && 全场得分 > 系数2
            if (fullInBall > coeNumOne && fullInBall > coeNumTwo) {
                // 下注no3=1的位置 全赢
                if (1 == no3) {
                    return true;
                } else {
                    // 下注no3=2的位置 全输
                    return false;
                }
            }
            // 全场得分 > 系数1 && 全场得分 = 系数2
            else if (fullInBall > coeNumOne && fullInBall == coeNumTwo) {
                // 下注no3=1的位置 半赢
                if (1 == no3) {
                    return true;
                } else {
                    // 下注no3=2的位置 半输
                    return false;
                }
            }
            // 全场得分 == 系数1 && 全场得分 < 系数2
            else if (fullInBall == coeNumOne && fullInBall < coeNumTwo) {
                // 下注no3=1 半输
                if (1 == no3) {
                    return false;
                } else {
                    // 下注no3=2 半赢
                    return true;
                }
            }
            // 全场得分 < 系数1 && 全场得分 < 系数2
            else if (fullInBall < coeNumOne && fullInBall < coeNumTwo) {
                // 下注no3=1 全输
                if (1 == no3) {
                    return false;
                } else {
                    // 下注no3=2 全赢
                    return true;
                }
            }
            // 否则 系数可能有误
            else {
                throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
            }
        }
    }


    /**
     * 足球全场让球
     *
     * @param selectedOption
     * @param vpv
     * @return
     */
    private boolean ftFullCourtLetBall(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // 获取下注的点
        int no3 = selectedOption.getNo3();
        int mbFullInBall;
        int tgFullInBall;
        // 获取主客队比分
        try {
            mbFullInBall = Integer.parseInt(vpv.getMbInBall());
            tgFullInBall = Integer.parseInt(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        // 不能根据match的Strong判断强弱队，要根据下注selectedOption中coeNum的‘正’‘负’判断强弱队.因为滚球赛事中强弱队有可能不断变化
        // 如果下注是主队并且下注系数不包含'-',或者下注客队并且下注系数包含'-'.说明主队是强队
        boolean mbIsStrong = (1 == selectedOption.getNo3() && !selectedOption.getCoeNum().contains("-"))
                || (2 == selectedOption.getNo3() && selectedOption.getCoeNum().contains("-"));
        if (mbIsStrong) {
            // 单系数
            if (!selectedOption.getCoeNum().contains("/")) {
                double coeNum = Math.abs(Double.parseDouble(selectedOption.getCoeNum()));
                // 主队得分 - 客队得分 - 系数 > 0
                if (mbFullInBall - tgFullInBall - coeNum > 0) {
                    // 下注主队 全赢
                    if (1 == no3) {
                        return true;
                    } else {
                        // 下注客队 全输
                        return false;
                    }
                }
                // 主队得分 - 客队得分 - 系数 = 0
                if (mbFullInBall - tgFullInBall - coeNum == 0) {
                    // 下注主队 走水.下注客队 走水
                    return false;
                }
                // 主队得分 - 客队得分 - 系数 < 0
                if (mbFullInBall - tgFullInBall - coeNum < 0) {
                    // 下注主队 全输
                    if (1 == no3) {
                        return false;
                    } else {
                        // 下注客队 全赢
                        return true;
                    }
                }
            } else {
                // 双系数(如"0.5 / 1")
                double coeNumOne = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[0]));
                double coeNumTwo = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[1]));
                // 主队得分 - 客队得分 - 系数1 > 0 && 主队得分 - 客队得分 - 系数2 > 0
                if (mbFullInBall - tgFullInBall - coeNumOne > 0 && mbFullInBall - tgFullInBall - coeNumTwo > 0) {
                    // 下注主队 全赢
                    if (1 == no3) {
                        return true;
                    } else {
                        // 下注客队 全输
                        return false;
                    }
                }
                // 主队得分 - 客队得分 - 系数1 > 0 && 主队得分 - 客队得分 - 系数2 = 0
                else if (mbFullInBall - tgFullInBall - coeNumOne > 0 && mbFullInBall - tgFullInBall - coeNumTwo == 0) {
                    // 下注主队 半赢
                    if (1 == no3) {
                        return true;
                    } else {
                        // 下注客队 半输
                        return false;
                    }
                }
                // 主队得分 - 客队得分 - 系数1 == 0 && 主队得分 - 客队得分 - 系数2 < 0
                else if (mbFullInBall - tgFullInBall - coeNumOne == 0 && mbFullInBall - tgFullInBall - coeNumTwo < 0) {
                    // 下注主队 半输
                    if (1 == no3) {
                        return false;
                    } else {
                        // 下注客队 半赢
                        return true;
                    }
                }
                // 主队得分 - 客队得分 - 系数1 < 0 && 主队得分 - 客队得分 - 系数2 < 0
                else if (mbFullInBall - tgFullInBall - coeNumOne < 0 && mbFullInBall - tgFullInBall - coeNumTwo < 0) {
                    // 下注主队 全输
                    if (1 == no3) {
                        return false;
                    } else {
                        // 下注客队 全赢
                        return true;
                    }
                }
                // 否则 系数可能有误
                else {
                    throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
                }
            }
        } else {
            // 客队是强队
            // 单系数
            if (!selectedOption.getCoeNum().contains("/")) {
                double coeNum = Math.abs(Double.parseDouble(selectedOption.getCoeNum()));
                // 客队得分 - 主队得分 - 系数 > 0
                if (tgFullInBall - mbFullInBall - coeNum > 0) {
                    // 下注客队 全赢
                    if (2 == no3) {
                        return true;
                    } else {
                        // 下注主队 全输
                        return false;
                    }
                }
                // 客队得分 - 主队得分 - 系数 = 0
                else if (tgFullInBall - mbFullInBall - coeNum == 0) {
                    // 下注主队 走水.下注客队 走水
                    return false;
                }
                // 客队得分 - 主队得分 - 系数 < 0
                else {
                    // 下注客队 全输
                    if (2 == no3) {
                        return false;
                    } else {
                        // 下注主队 全赢
                        return true;
                    }
                }
            } else {
                // 双系数(如"0.5 / 1")
                double coeNumOne = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[0]));
                double coeNumTwo = Math.abs(Double.parseDouble(selectedOption.getCoeNum().split("/")[1]));
                // 客队得分 - 主队得分 - 系数1 > 0 && 客队得分 - 主队得分 - 系数2 > 0
                if (tgFullInBall - mbFullInBall - coeNumOne > 0 && tgFullInBall - mbFullInBall - coeNumTwo > 0) {
                    // 下注客队 全赢
                    if (2 == no3) {
                        return true;
                    } else {
                        // 下注主队 全输
                        return false;
                    }
                }
                // 客队得分 - 主队得分 - 系数1 > 0 && 客队得分 - 主队得分 - 系数2 = 0
                else if (tgFullInBall - mbFullInBall - coeNumOne > 0 && tgFullInBall - mbFullInBall - coeNumTwo == 0) {
                    // 下注客队 半赢
                    if (2 == no3) {
                        return true;
                    } else {
                        // 下注主队 半输
                        return false;
                    }
                }
                // 客队得分 - 主队得分 - 系数1 == 0 && 客队得分 - 主队得分 - 系数2 < 0
                else if (tgFullInBall - mbFullInBall - coeNumOne == 0 && tgFullInBall - mbFullInBall - coeNumTwo < 0) {
                    // 下注客队 半输
                    if (2 == no3) {
                        return false;
                    } else {
                        // 下注主队 半赢
                        return true;
                    }
                }
                // 客队得分 - 主队得分 - 系数1 < 0 && 客队得分 - 主队得分 - 系数2 < 0
                else if (tgFullInBall - mbFullInBall - coeNumOne < 0 && tgFullInBall - mbFullInBall - coeNumTwo < 0) {
                    // 下注客队 全输
                    if (2 == no3) {
                        return false;
                    } else {
                        // 下注主队 全赢
                        return true;
                    }
                }
                // 否则 系数可能有误
                else {
                    throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
                }
            }
        }
        return false;
    }


    /**
     * 足球独赢
     *
     * @param selectedOption
     * @param vpv
     * @return
     */
    private boolean ftFullCourtWinSimplex(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // no3是下注的内容
        int no3 = selectedOption.getNo3();
        Integer mbFullInBall;
        Integer tgFullInBall;
        // 获取主客队比分
        try {
            mbFullInBall = Integer.valueOf(vpv.getMbInBall());
            tgFullInBall = Integer.valueOf(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        // 如果no3 = 1 主队比分 > 客队比分 中奖
        if (1 == no3 && (mbFullInBall > tgFullInBall)) {
            return true;
        }
        // 如果no3 = 2 客队比分 > 主队比分 中奖
        else if (2 == no3 && (tgFullInBall > mbFullInBall)) {
            return true;
        }
        // 如果no3 = 3 客队比分 = 主队比分 中奖
        else if (3 == no3 && (tgFullInBall.equals(mbFullInBall))) {
            return true;
        }
        // 否则 输
        else {
            return false;
        }
    }

    /**
     * 篮球独赢
     */
    private boolean bkFullCourtWinSimplex(CrownMatchSimplex selectedOption, CrownMatchViewPointVO vpv) {
        // no3是下注的内容
        int no3 = selectedOption.getNo3();
        Integer mbFullInBall;
        Integer tgFullInBall;
        // 获取主客队比分
        try {
            mbFullInBall = Integer.valueOf(vpv.getMbInBall());
            tgFullInBall = Integer.valueOf(vpv.getTgInBall());
        }catch (Exception e){
            return false;
        }
        // 如果no3 = 1 主队比分 > 客队比分 中奖
        if (1 == no3 && (mbFullInBall > tgFullInBall)) {
            return true;
        }
        // 如果no3 = 2 客队比分 > 主队比分 中奖
        else if (2 == no3 && (tgFullInBall > mbFullInBall)) {
            return true;
        }
        // 否则 输
        else {
            return false;
        }
    }

    /**
     * 观点列表查询
     *
     * @param pageNumber    页码
     * @param pageSize      页数
     * @param searchKeyword 查询条件
     * @param matchType     赛事类型
     * @param sortType      排序类型 默认为观点发布时间倒序，1、连胜排序，2、命中率排序
     * @return
     */
    @Override
    public Pagination listPage(Integer pageNumber, int pageSize, String searchKeyword, String userId, MatchTypeEnum matchType, String sortType) {
        //列表sql
        Sql sql = Sqls.create(
                "SELECT p.id, p.userId, p.title, p.sketch, p.matchType, p.showBets, p.price, p.ctAt, p.result, p.refundable, " +
                        "   u.nickName, u.headPicture, u.certified, " +
                        "   m.league, m.mb_team as mbTeam, m.tg_team as tgTeam, m.mb_in_ball_hf as mbInBallHalf, m.mb_in_ball as mbInBall, m.tg_in_ball_hf as tgInBallHalf, m.tg_in_ball as tgInBall, m.date_time as dateTime, m.stage, " +
                        "   l.matchCount, l.winCount, l.type, l.hitRate," +
                        "   (SELECT COUNT(1) > 0 FROM crown_view_point_order WHERE vpId = p.id AND userId = @userId) as paid " +
                        "FROM crown_view_point p " +
                        "LEFT JOIN `user` u ON p.userId = u.id " +
                        "LEFT JOIN crown_match m ON p.matchId = m.id " +
                        "LEFT JOIN (SELECT userId, type, matchCount, winCount, winCount/matchCount as hitRate FROM crown_view_point_label " +
                        "   WHERE delFlag = 0 AND type = @type GROUP BY userId) l ON p.userId = l.userId " +
                        "$condition ");
        //总数sql
        Sql countSql = Sqls.create("SELECT COUNT(1) " +
                "FROM crown_view_point p " +
                "LEFT JOIN `user` u ON p.userId = u.id " +
                "LEFT JOIN crown_match m ON p.matchId = m.id " +
                "$condition ");
        Cnd cnd = Cnd.where("p.delFlag", "=", 0)
                .and("p.status", "=", ViewStatusEnum.PASS);
        sql.setParam("userId", userId);
        String sort = "ORDER BY p.ctAt DESC";
        String type = "all";
        if (Strings.isNotBlank(sortType)) {
            switch (sortType) {
                case "1":
                    sort = "ORDER BY l.winCount DESC";
                    type = "seriesWin";
                    break;
                case "2":
                    sort = "ORDER BY l.hitRate DESC";
                    break;
            }
        }
        sql.setParam("type", type);
        if (null != matchType) {
            cnd.and("p.matchType", "=", matchType);
        }
        if (Strings.isNotBlank(searchKeyword)) {
            searchKeyword = "%" + searchKeyword + "%";
            cnd.and(Cnd.exps("p.title", "LIKE", searchKeyword)
                    .or("u.nickName", "LIKE", searchKeyword)
                    .or("m.league", "LIKE", searchKeyword));
        }
        sql.setCondition(cnd);
        sql.appendSourceSql(sort);
        countSql.setCondition(cnd);

        Pagination pagination = dbService.listPage(CrownViewPointVO.class, pageNumber, pageSize, sql.toString(), countSql.toString());
        List<CrownViewPointVO> crownViewPointVOList = pagination.getList(CrownViewPointVO.class);
        for (CrownViewPointVO crownViewPointVO : crownViewPointVOList) {
            if (!crownViewPointVO.isPaid() && crownViewPointVO.getStage().equals("finished")) {
                crownViewPointVO.setPaid(true);
            }
        }
        return pagination;
    }

    @Override
    public Map selfList(Integer pageNumber, int pageSize, String appid, MatchTypeEnum matchType, String userId) {
        Sql sql = Sqls.create("select v.result, v.refundable, v.title, m.type, m.date_time dateTime, m.league, " +
                "   m.mb_team mbTeam, m.tg_team tgTeam, u.nickName, u.phone, u.headPicture, u.certified, " +
                "   v.id, v.userId, v.sketch, v.showBets, v.ctAt, v.price, v.matchType " +
                "from crown_view_point v ");
        Sql countSql = Sqls.create("select count(1) from crown_view_point v ");
        String joinSql = "left join user u on u.id = v.userId " +
                "left join crown_match m on m.id = v.matchId  " +
                "$condition ";
        sql.appendSourceSql(joinSql);
        countSql.appendSourceSql(joinSql);
        Cnd cnd = Cnd.where("v.delFlag", "=", 0);
        if (Strings.isNotBlank(userId)) {
            appid = userId;
            cnd.and("v.status", "=", ViewStatusEnum.PASS);
        }
        cnd.and("v.userId", "=", appid);
        if (null != matchType) {
            cnd.and("v.matchType", "=", matchType);
        }
        sql.setCondition(cnd);
        sql.appendSourceSql("order by ctAt desc");
        countSql.setCondition(cnd);

        Sql userSql = Sqls.create("SELECT id, nickName, headPicture, sign FROM user WHERE id = @userId");
        userSql.setParam("userId", appid);
        return Result.createMap("record", dbService.fetchCnd(CrownViewPointLabel.class, Cnd.where("userId", "=", appid)
                        .and("type", "=", "all")
                        .and("delFlag", "=", 0)),
                "Pagination", dbService.listPage(CrownMatchViewPointVO.class, pageNumber, pageSize, sql.toString(), countSql.toString()),
                "userInfo", dbService.fetchSql(User.class, userSql.toString()));
    }

    @Override
    public CrownMatchViewPointVO detail(String id, String appid) {

        CrownViewPoint viewPoint = this.fetch(id);
        //比赛已结束||无需购买||已购买||作者
        if (matchService.fetch(viewPoint.getMatchId()).getStage().equals("finished")
                || viewPoint.getPrice().compareTo(BigDecimal.ZERO) == 0
                || orderService.count(Cnd.where("vpId", "=", id).and("userId", "=", appid)) != 0
                || viewPoint.getUserId().equals(appid)) {
            Sql sql = Sqls.create("select v.result,refundable,true as paid,u.nickName,u.phone,u.headPicture,u.certified, " +
                    "   league,m.type,m.date_time as dateTime ,m.mb_team as mbTeam,m.tg_team as tgTeam," +
                    "   v.id,matchId,v.userId,title,content,showBets,selectedOption,v.ctAt,price, " +
                    "   l.matchCount, l.winCount, l.hitRate " +
                    " from crown_view_point v")
                    .appendSourceSql(" left join user u on v.userId = u.id")
                    .appendSourceSql("left join crown_match m on m.id = matchId")
                    .appendSourceSql("left join (select userId, type, matchCount, winCount, winCount/matchCount as hitRate " +
                            "from crown_view_point_label " +
                            "where delFlag = 0 and type = 'all' group by userId) l ON v.userId = l.userId")
                    .appendSourceSql(" where v.id=@id and v.delFlag=0")
                    .appendSourceSql(" limit 1")
                    .setParam("id", id);
            CrownMatchViewPointVO vp = dbService.fetchSql(CrownMatchViewPointVO.class, sql.toString());
            return vp;
        } else {
            CrownMatchViewPointVO vp = dbService.fetchSql(CrownMatchViewPointVO.class, Sqls.create("select v.result,refundable,false as paid,u.nickName,u.phone,u.headPicture,u.certified, " +
                    "   league,m.type,m.date_time as dateTime ,m.mb_team as mbTeam,m.tg_team as tgTeam," +
                    "   v.id,matchId,v.userId,v.title,showBets,v.ctAt,price, " +
                    "   l.matchCount, l.winCount, l.hitRate " +
                    "from crown_view_point v " +
                    "left join crown_match m on m.id = matchId " +
                    "left join user u on u.id = v.userId " +
                    "left join (select userId, type, matchCount, winCount, winCount/matchCount as hitRate " +
                    "   from crown_view_point_label " +
                    "   where delFlag = 0 and type = 'all' group by userId) l ON v.userId = l.userId " +
                    "where v.id=@id and v.delFlag=0 limit 1").setParam("id", id).toString());
            return vp;
        }
    }

    /**
     * 关注用户观点列表查询
     *
     * @param pageNumber
     * @param pageSize
     * @param userId
     * @return
     */
    @Override
    public Pagination listPageVo(Integer pageNumber, int pageSize, String userId) {


        Sql sql = Sqls.create(
                "SELECT p.id, p.userId, p.title, p.sketch, p.matchType, p.showBets, p.price, p.ctAt, p.result, p.refundable, " +
                        "   u.nickName, u.headPicture, u.certified, " +
                        "   m.league, m.mb_team as mbTeam, m.tg_team as tgTeam, m.mb_in_ball as mbInBall, m.tg_in_ball as tgInBall, m.date_time as dateTime, " +
                        "   l.matchCount, l.winCount, l.type, l.hitRate, " +
                        "   (SELECT COUNT(1) > 0 FROM crown_view_point_order WHERE vpId = p.id AND userId = f.userId) as paid " +
                        "FROM crown_view_point p " +
                        "LEFT JOIN user_focus f ON p.userId = f.anchorId " +
                        "LEFT JOIN `user` u ON f.anchorId = u.id " +
                        "LEFT JOIN crown_match m ON p.matchId = m.id " +
                        "LEFT JOIN (SELECT userId, type, matchCount, winCount, winCount/matchCount as hitRate FROM crown_view_point_label " +
                        "   WHERE delFlag = 0 AND type = 'all' GROUP BY userId) l ON p.userId = l.userId " +
                        "$condition ");
        Sql countSql = Sqls.create("SELECT COUNT(1) " +
                "FROM crown_view_point p " +
                "LEFT JOIN user_focus f ON p.userId = f.anchorId " +
                "$condition ");
        Cnd cnd = Cnd.where("f.userId", "=", userId)
                .and("f.delFlag", "=", 0)
                .and("p.status", "=", ViewStatusEnum.PASS)
                .and("p.delFlag", "=", 0);
        sql.setCondition(cnd);
        sql.appendSourceSql("ORDER BY l.hitRate, p.ctAt DESC ");
        countSql.setCondition(cnd);
        return dbService.listPage(CrownViewPointVO.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    /**
     * 战绩榜
     *
     * @param pageNumber
     * @param pageSize
     * @param type       类型：1、近10场，2、近30场，3、连红，4、明灯
     * @return
     */
    @Override
    public Pagination recordListPage(Integer pageNumber, int pageSize, String type) {
        Sql sql = Sqls.create("SELECT u.id as userId, u.nickName, u.headPicture, u.certified, " +
                "l.matchCount, l.winCount, l.totalOdds, l.winCount/l.matchCount as hitRate " +
                "FROM crown_view_point_label l " +
                "LEFT JOIN `user` u ON l.userId = u.id ");
        Sql countSql = Sqls.create("SELECT COUNT(1) " +
                "FROM crown_view_point_label l " +
                "LEFT JOIN `user` u ON l.userId = u.id ");
        if (Strings.isBlank(type)) {
            type = "1";
        }
        //排序信息，默认根据回报率排序
        String sort = "ORDER BY l.totalOdds DESC";
        String joinStr;
        switch (type) {
            case "1":
                //近10场统计   低于10场 需查询10场以内最大场次
                joinStr = "LEFT JOIN (SELECT userId, MAX(matchCount) as maxCount " +
                        "FROM crown_view_point_label " +
                        "WHERE delFlag = 0 AND type='last' AND matchCount <= 10 GROUP BY userId) li ON l.userId = li.userId " +
                        "WHERE l.matchCount = li.maxCount " +
                        "AND l.type = 'last' ";
                sql.appendSourceSql(joinStr);
                countSql.appendSourceSql(joinStr);
                break;
            case "2":
                //近30场统计 低于30场 需查询30场以内最大场次
                joinStr = "LEFT JOIN (SELECT userId, MAX(matchCount) as maxCount " +
                        "   FROM crown_view_point_label " +
                        "   WHERE delFlag = 0 AND type='last' AND matchCount <= 30 GROUP BY userId) li ON l.userId = li.userId " +
                        "WHERE l.matchCount = li.maxCount " +
                        "AND l.type = 'last' ";
                sql.appendSourceSql(joinStr);
                countSql.appendSourceSql(joinStr);
                break;
            case "3":
                //连红统计
                sql.appendSourceSql("WHERE l.type = 'seriesWin'");
                countSql.appendSourceSql("WHERE l.type = 'seriesWin'");
                sort = "ORDER BY l.matchCount DESC";
                break;
            case "4":
                //连黑统计
                sql.appendSourceSql("WHERE l.type = 'seriesTransport'");
                countSql.appendSourceSql("WHERE l.type = 'seriesTransport'");
                sort = "ORDER BY l.matchCount DESC";
                break;
            default:
                Result.breakWith("类型不正确");
        }
        sql.appendSourceSql("AND l.delFlag = 0 ");
        countSql.appendSourceSql("AND l.delFlag = 0 ");
        sql.appendSourceSql(sort);
        return dbService.listPage(CrownViewPointRecordVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    /**
     * 足篮专家
     *
     * @param pageNumber
     * @param pageSize
     * @param userId
     * @return
     */
    @Override
    public Pagination expertListPage(Integer pageNumber, int pageSize, String userId) {
        Sql sql = Sqls.create("SELECT u.id as userId, u.nickName, u.headPicture, u.sign, " +
                    "IFNULL(l.matchCount, 0) as matchCount, IFNULL(l.winCount, 0) as winCount, IFNULL(l.totalOdds, 0) as totalOdds, " +
                    "(SELECT IFNULL(AVG(odds), 0) FROM crown_view_point WHERE delFlag = 0 AND userId = u.id AND result = 1) as averageOdds, " +
                    "(SELECT COUNT(1) FROM crown_view_point p " +
                        "LEFT JOIN crown_match m ON p.matchId = m.id " +
                        "WHERE m.date_time > NOW() AND p.delFlag = 0 AND p.userId = u.id) as saleNum, " +
                    "(SELECT COUNT(1) > 0 FROM user_focus WHERE anchorId = u.id AND userId = @userId AND delFlag = 0) as isFocus " +
                "FROM `user` u " +
                "LEFT JOIN crown_view_point_label l ON u.id = l.userId AND l.type = @type AND l.delFlag = 0 " +
                "WHERE u.certified = 1 " +
                "ORDER BY l.totalOdds DESC ");
        Sql countSql = Sqls.create("SELECT COUNT(1) FROM `user` WHERE certified = 1 ");
        sql.setParam("type", "all");
        sql.setParam("userId", userId);
        return dbService.listPage(CrownViewPointExpertVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    /**
     * 后台观点分页查询
     *
     * @param pageNumber
     * @param pageSize
     * @param searchKeyword
     * @param searchDate
     * @param matchType
     * @param status
     * @return
     */
    @Override
    public Pagination listPage(Integer pageNumber, int pageSize, String searchKeyword, String[] searchDate, MatchTypeEnum matchType, ViewStatusEnum status) {
        Sql sql = Sqls.create("SELECT cvp.id, cvp.no, cvp.title, cvp.content, cvp.matchType, cvp.showBets, cvp.result, cvp.refundable, cvp.ctAt, cvp.status, cvp.remark, " +
                "u.nickName, u.headPicture, cm.league, " +
                "(SELECT COUNT(1) FROM crown_view_point_order WHERE vpId = cvp.id AND delFlag = 0) as saleNum " +
                "FROM crown_view_point cvp " +
                "LEFT JOIN user u ON cvp.userId = u.id " +
                "LEFT JOIN crown_match cm ON cvp.matchId = cm.id " +
                "WHERE cvp.delFlag = 0");
        Sql countSql = Sqls.create("SELECT COUNT(1) count " +
                "FROM crown_view_point cvp " +
                "LEFT JOIN user u ON cvp.userId = u.id " +
                "WHERE cvp.delFlag = 0");
        if (Strings.isNotBlank(searchKeyword)) {
            String appendSql = "AND " +
                    "(u.nickName LIKE CONCAT('%', @searchKeyword, '%') " +
                    "OR u.phone LIKE CONCAT('%', @searchKeyword, '%') " +
                    "OR u.userName LIKE CONCAT('%', @searchKeyword, '%') " +
                    "OR cvp.no LIKE CONCAT('%', @searchKeyword, '%')) ";
            sql.appendSourceSql(appendSql);
            sql.setParam("searchKeyword", searchKeyword);
            countSql.appendSourceSql(appendSql);
            countSql.setParam("searchKeyword", searchKeyword);
        }
        if (null != searchDate && searchDate.length != 0) {
            sql.appendSourceSql("AND cvp.ctAt >= @startTime ");
            sql.appendSourceSql("AND cvp.ctAt <= @endTime ");
            sql.setParam("startTime", Times.d2TS(Times.D(searchDate[0])));
            sql.setParam("endTime", Times.d2TS(Times.D(searchDate[1])));
            countSql.appendSourceSql("AND cvp.ctAt >= @startTime ");
            countSql.appendSourceSql("AND cvp.ctAt <= @endTime ");
            countSql.setParam("startTime", Times.d2TS(Times.D(searchDate[0])));
            countSql.setParam("endTime", Times.d2TS(Times.D(searchDate[1])));
        }
        if (matchType != null) {
            sql.appendSourceSql("AND cvp.matchType = @matchType ");
            sql.setParam("matchType", matchType);
            countSql.appendSourceSql("AND cvp.matchType = @matchType ");
            countSql.setParam("matchType", matchType);
        }
        if (status != null) {
            sql.appendSourceSql("AND cvp.status = @status ");
            sql.setParam("status", status);
            countSql.appendSourceSql("AND cvp.status = @status ");
            countSql.setParam("status", status);
        }
        sql.appendSourceSql("ORDER BY cvp.ctAt DESC");
        return dbService.listPage(CrownViewPointManagerVO.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    /**
     * 观点发布
     *
     * @param viewPoint
     * @param appid
     */
    @Override
    @Aop(TransAop.READ_COMMITTED)
    public SysMsg add(CrownViewPoint viewPoint, String appid) {
        //观点内容、标题敏感词过滤
        viewPoint.setTitle(sysSensitiveService.filter(viewPoint.getTitle()));
        viewPoint.setContent(sysSensitiveService.filter(viewPoint.getContent()));
        //获取全局参数
        SysParam sysParam = sysParamService.fetch();
        Integer viewTitleMinLength = sysParam.getViewTitleMinLength();
        Integer viewTitleMaxLength = sysParam.getViewTitleMaxLength();
        if (viewPoint.getTitle().length() < viewTitleMinLength || viewPoint.getTitle().length() > viewTitleMaxLength) {
            Result.breakWith("观点标题请控制在" + viewTitleMinLength + "到" + viewTitleMaxLength + "个字以内");
        }
        Integer viewContentMinLength = sysParam.getViewContentMinLength();
        if (viewPoint.getContent().length() < viewContentMinLength) {
            Result.breakWith("观点内容必须在" + viewContentMinLength + "个字以上");
        }
        if (viewPoint.getPrice() == null || viewPoint.getPrice().compareTo(BigDecimal.ZERO) < 0) {
            Result.breakWith("金额有误");
        }
        if (Strings.isBlank(viewPoint.getMatchId())) {
            Result.breakWith("尚未选择对应赛事");
        }
        if (Strings.isBlank(viewPoint.getSelectedOption())) {
            Result.breakWith("尚未选择具体玩法");
        }
        User user = dbService.fetchCnd(User.class, Cnd.where("id", "=", appid));
        int count = this.count(Cnd.where("userId", "=", appid)
                .and("matchId", "=", viewPoint.getMatchId())
                .and("delFlag", "=", 0));
        if (count > 0) {
            Result.breakWith("不可重复发布同一场比赛的观点");
        }
        //判断一天内发布的观点数量是否达到限制
        //today 00:00
        long today = Times.ams(Times.nextDay(0)) / 1000;
        //tomorrow 00:00
        long tomorrow = Times.ams(Times.afterDay()) / 1000;
        int countNum = this.count(Cnd.where("userId", "=", appid).and("ctAt", ">=", today).and("ctAt", "<=", tomorrow));
        if (countNum >= sysParam.getViewReleaseLimit()) {
            Result.breakWith("观点发布数量已达到限制");
        }
        viewPoint.setCtAt(Times.getTS());
        //未结算状态
        viewPoint.setResult(0);
        viewPoint.setUserId(appid);
        CrownMatchSimplex selectedOption = JSONUtil.parseStringToJavaBean(CrownMatchSimplex.class, viewPoint.getSelectedOption());
        //回报统计字段
        viewPoint.setOdds(selectedOption.getOdds());
        //观点单号
        viewPoint.setNo(Id.createOrderNo());
        this.insert(viewPoint);

        //构建消息通知
        SysMsg msg = sysMsgService.createMsg("system", "发布观点提醒",
                String.format("<p>消息内容:观点单号[%s]用户[%s]手机号[%s]于<span style='color:red'>%s</span> 发布了观点，标题[%s]，请点击前往审核。<a href=%s style='color:blue'>点击处理</a></p>", viewPoint.getNo(), user.getUserName(), user.getPhone(), DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"), viewPoint.getTitle(), "/platform/user/view?no=" + viewPoint.getNo()),
                null);
        //插入通知
        sysMsgService.saveMsg(msg, null);
        return msg;
    }

    /**
     * 我的粉丝列表
     *
     * @param pageNumber
     * @param pageSize
     * @param anchorId
     * @return
     */
    @Override
    public Pagination funList(Integer pageNumber, int pageSize, String anchorId) {
        Sql sql = Sqls.create("SELECT uf.userId, uf.opAt, u.nickName, u.headPicture, u.sign, u.certified," +
                "   (SELECT COUNT(1) > 0 FROM user_focus WHERE anchorId = u.id AND userId = uf.anchorId AND delFlag = 0) as isFocus " +
                "FROM user_focus uf " +
                "LEFT JOIN user u ON uf.userId = u.id " +
                "WHERE uf.anchorId = @anchorId " +
                "AND uf.delFlag = 0 " +
                "ORDER BY uf.opAt DESC");
        Sql countSql = Sqls.create("SELECT COUNT(1) FROM user_focus WHERE anchorId = @anchorId AND delFlag = 0");
        sql.setParam("anchorId", anchorId);
        return dbService.listPage(UserFocusVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    /**
     * 观点重新结算
     *
     * @param matchId
     */
    @Override
    public void renewViewPoint(String matchId) {
        //查询关联赛事的已结算观点
        List<CrownViewPoint> viewPoints = this.query(Cnd.where("matchId", "=", matchId)
                .and("result", "!=", 0));
        for (CrownViewPoint viewPoint : viewPoints) {
            //若观点为中，从发布者处退回每笔已结算订单
            if (viewPoint.getResult() == 1) {
                if (viewPoint.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                    for (CrownViewPointOrder order : orderService.query(Cnd.where("vpId", "=", viewPoint.getId()))) {
                        UserAccountRecord userAccountRecord = accountRecordService.fetch(Cnd.where("userId", "=", viewPoint.getUserId())
                                .and("bizId", "=", order.getId()));
                        accountRecordService.add(viewPoint.getUserId(), userAccountRecord.getOperateAmount(), BizTypeEnum.RETURN_VIEW_POINT, userAccountRecord.getId());
                        //设置bizId = 原bizId + 重新结算
                        accountRecordService.update(Chain.make("bizId", order.getId() + "--重新结算"), Cnd.where("id", "=", userAccountRecord.getId()));
                    }
                }
            } else if (viewPoint.getResult() == -1) {
                //若观点为不中，判断观点是否为不中退的类型，若是则扣除用户金额，若不是则扣除发布者金额
                if (viewPoint.getPrice().compareTo(BigDecimal.ZERO) > 0) {
                    if (viewPoint.getRefundable()) {
                        //扣除用户金额
                        for (CrownViewPointOrder order : orderService.query(Cnd.where("vpId", "=", viewPoint.getId()))) {
                            UserAccountRecord userAccountRecord = accountRecordService.fetch(Cnd.where("userId", "=", viewPoint.getUserId())
                                    .and("bizId", "=", order.getId()));
                            accountRecordService.add(order.getUserId(), userAccountRecord.getOperateAmount(), BizTypeEnum.RETURN_VIEW_POINT, userAccountRecord.getId());
                            //设置bizId = 原bizId + 重新结算
                            accountRecordService.update(Chain.make("bizId", order.getId() + "--重新结算"), Cnd.where("id", "=", userAccountRecord.getId()));
                        }
                    } else {
                        //扣除发布者金额
                        for (CrownViewPointOrder order : orderService.query(Cnd.where("vpId", "=", viewPoint.getId()))) {
                            UserAccountRecord userAccountRecord = accountRecordService.fetch(Cnd.where("userId", "=", viewPoint.getUserId())
                                    .and("bizId", "=", order.getId()));
                            accountRecordService.add(viewPoint.getUserId(), userAccountRecord.getOperateAmount(), BizTypeEnum.REFUND_VIEW_POINT, userAccountRecord.getId());
                            //设置bizId = 原bizId + 重新结算
                            accountRecordService.update(Chain.make("bizId", order.getId() + "--重新结算"), Cnd.where("id", "=", userAccountRecord.getId()));
                        }
                    }
                }
            }
            //修改观点结果为等待结算
            this.update(Chain.make("result", 0), Cnd.where("id", "=", viewPoint.getId()));
        }
    }

    @Override
    public Pagination matchList(Integer pageNo, Integer pageSize, MatchTypeEnum matchType) {
        Cnd where = Cnd.where("stage", "in", "'FUTURE','BROWSE'");
        if (matchType != null) {
            where.and("type", "=", matchType);
        }
        // 当前系统时间转美东
        String edt = DateUtil.sysConvertEdt(new Date());
        where.and("date_time", ">", edt);
        // 只通过match的stage判断还不够，因为如果有的赛果没有爬到它的stage停留在browse不会再变。所以要筛选现在时间之后的
        return matchService.listPage(pageNo, pageSize, where.orderBy("league", "desc").orderBy("date_time", "asc"));

    }


}
